/*
 * Copyright (c) 2006-2011, Petr Panteleyev
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.livejournal;

import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.TreeMap;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import org.panteleyev.blogapi.IBlogEntry;
import org.panteleyev.blogclient.AboutDialog;
import org.panteleyev.blogclient.BloggerFrame;
import org.panteleyev.blogclient.Icon;
import org.panteleyev.blogclient.MainClass;
import org.panteleyev.blogclient.ProfileDialog;
import org.panteleyev.blogclient.UserProfile;
import org.panteleyev.blogclient.UserProfileType;
import org.panteleyev.fotobilder.FBAccount;
import org.panteleyev.fotobilder.FBPicture;
import org.panteleyev.fotobilder.FotoBilderException;
import org.panteleyev.ljapi.LJAccount;
import org.panteleyev.ljapi.LJCheckFriendsData;
import org.panteleyev.ljapi.LJComment;
import org.panteleyev.ljapi.LJCommentCacheInfo;
import org.panteleyev.ljapi.LJCommentMetaData;
import org.panteleyev.ljapi.LJCommentMetaDataUpdate;
import org.panteleyev.ljapi.LJEvent;
import org.panteleyev.ljapi.LJException;
import org.panteleyev.ljapi.LJFriend;
import org.panteleyev.ljapi.LJGroup;
import org.panteleyev.ljapi.LJModeNotSupportedException;
import org.panteleyev.ljapi.LJMood;
import org.panteleyev.ljapi.LJProperties;
import org.panteleyev.ljapi.LJTag;
import org.panteleyev.ljapi.LJUserpic;
import org.panteleyev.swing.OSUtil;
import org.panteleyev.swing.WindowManager;
import org.panteleyev.swing.WindowManagerEnumerator;
import org.panteleyev.utilities.MD5;

import com.google.common.collect.ImmutableList;
import org.panteleyev.blogclient.IPhotoUserProfile;

final public class LJUserProfile extends UserProfile<LJEvent> implements IPhotoUserProfile {
    private final static long serialVersionUID = 20100206L;

    /* File names */
    private static final String FRIENDS_FILE        = "friends.pb";
    private static final String BANNED_FILE         = "banned.pb";
    private static final String GROUPS_FILE         = "groups.pb";
    private static final String JOURNALS_FILE       = "journals.pb";
    private static final String TAGS_FILE           = "tags.pb";
    private static final String MOODS_FILE          = "moods.pb";
    private static final String COMMENTS_FILE       = "comments.pb";
    private static final String USERPICS_FILE       = "userpics.pb";
    private static final String PICTURES_FILE       = "pictures.pb";
    private static final String USERMAP_FILE_NAME   = "usermap.pb";
    private static final String COMM_META_FILE_NAME = "comm_meta.pb";

    /* Serializable fields */
    private boolean                 checkFriends = false;
    private int                     mask = 1;
    private boolean                 remindBirthdays = true;
    private int                     remindBirthdaysInterval = 3;
    private LJCommentMetaDataUpdate commMetaInfoUpdate = LJCommentMetaDataUpdate.ONCE;

    /* Transient fields */
    private transient LJAccount               _account;
    private transient FBAccount               fbAccount;
    private transient ArrayList<LJTag>        m_tags;
    private transient ArrayList<LJBannedUser> bannedUsers;
    private transient HashMap<LJUserpic, ImageIcon> userpicImages;

    /* CheckFriends related variables */
    private static java.util.Timer m_checkFriendsTimer;
    private final static Object m_checkTimerSync = new Object();

    private static int maxMoodID = 0;

    /* Actions */
    private transient AbstractAction openFriendsWindowAction;
    private transient AbstractAction historyWindowAction;
    private transient AbstractAction galleryAction;
    private transient AbstractAction consoleAction;
    private transient AbstractAction outboxAction;
    private transient AbstractAction editLastPostAction;
    private transient AbstractAction recentEntriesAction;
    private transient AbstractAction calendarAction;
    private transient AbstractAction webFriendsAction;

    private transient ArrayList<AbstractAction> profileActions;
    private transient ArrayList<AbstractAction> toolBarActions;
    private transient LJProperties  properties;


    /**
     * Creates a new instance of LJUserProfile
     */
    /*
    public LJUserProfile() {
        super(UserProfileType.LIVEJOURNAL, "");
        profileActions = new ArrayList<AbstractAction>();
        createActions();
        bannedUsers = new ArrayList<LJBannedUser>();
        fbAccount = new FBAccount("http://pics.livejournal.com/");
        userpicImages = new HashMap<LJUserpic, ImageIcon>();
    }
     *
     */

    public LJUserProfile(String name, String server) {
        super(UserProfileType.LIVEJOURNAL, name, server);
        setupProperties();
        profileActions = new ArrayList<>();
        bannedUsers = new ArrayList<>();
        if (!properties.getFotoBilderUrl().isEmpty()) {
            fbAccount = new FBAccount(properties.getFotoBilderUrl());
        }
        userpicImages = new HashMap<>();
        createActions();
    }

    private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
        stream.defaultReadObject();
        setupProperties();
        profileActions = new ArrayList<>();
        bannedUsers = new ArrayList<>();
        if (!properties.getFotoBilderUrl().isEmpty()) {
            fbAccount = new FBAccount(properties.getFotoBilderUrl());
        }
        userpicImages = new HashMap<>();
        createActions();
    }

    private void setupProperties() {
        /* Get server properties */
        String serverName = getServer();
        if (serverName.length() == 0) {
            serverName = LJServers.getDefaultServerName();
        }

        properties = LJServers.getProperties(serverName);
        if (properties == null) {
            throw new NullPointerException();
        }
    }

    public FBAccount getFbAccount() {
        return fbAccount;
    }

    public boolean getCheckFriends() {
        return checkFriends;
    }

    public void setCheckFriends(boolean b) {
        checkFriends = b;
    }

    public int getCheckFriendsMask() {
        return mask;
    }

    public void setCheckFriendsMask(int mask) {
        this.mask = mask;
    }

    public boolean getRemindBirthdays() {
        return remindBirthdays;
    }

    public void setRemindBirthdays(boolean r) {
        remindBirthdays = r;
    }

    public int getRemindBirthdaysInterval() {
        return remindBirthdaysInterval;
    }

    public void setRemindBirthdaysInterval(int i) {
        remindBirthdaysInterval = i;
    }

    public LJCommentMetaDataUpdate getCommentsMetaInfoUpdate() {
        return commMetaInfoUpdate;
    }

    public void setCommentsMetaInfoUpdate(LJCommentMetaDataUpdate u) {
        commMetaInfoUpdate = u;
    }

    public static int getMaxMoodID() { return maxMoodID; }

    public void setAccount(LJAccount account) { _account = account; }
    public LJAccount getAccount() { return _account; }

    public File getCommentsDirectory(boolean create) {
        File comments = new File(getCacheDirectory(), "comments");
        if (!comments.exists() && create) {
            comments.mkdir();
        }

        return comments;
    }

    public File getCommentsDirectory() {
        File comments = new File(getCacheDirectory(), "comments");
        if (!comments.exists()) {
            comments.mkdir();
        }

        return comments;
    }

    public File getCommentsPostingDirectory(String itemID) {
        File dir = new File(getCommentsDirectory(), itemID);
        if (!dir.exists()) {
            dir.mkdir();
        }

        return dir;
    }

    public int loadUserTags(ArrayList<LJTag> tags) {
        tags.clear();

        File fin = new File(getCacheDirectory(), TAGS_FILE);
        if (fin.exists()) {
            try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin))) {
                int count = in.readInt();
                tags.ensureCapacity(count);

                for (int i = 0; i < count; ++i) {
                    LJTag tag = (LJTag)in.readObject();
                    if (tag != null) {
                        tags.add(tag);
                    }
                }
            } catch (IOException | ClassNotFoundException ex) {
                MainClass.handleException(null, ex);
            }
        }

        return tags.size();
    }

    public void storeUserTags(ArrayList<LJTag> tags) {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), TAGS_FILE)))) {
            out.writeInt(tags.size());
            for (LJTag t : tags) {
                out.writeObject(t);
            }
        } catch (Exception ex) {
            MainClass.handleException(null, ex);
        }
    }

    public void storeSharedJournals(ArrayList<String> journals) {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), JOURNALS_FILE)))) {
            out.writeInt(journals.size());
            for (String s : journals) {
                out.writeObject(s);
            }
        } catch (Exception ex) {
            MainClass.handleException(null, ex);
        }
    }

    public ArrayList<String> loadSharedJournals() {
        ArrayList<String> journals = new ArrayList<>();

        File fin = new File(getCacheDirectory(), JOURNALS_FILE);
        if (!fin.exists()) {
            return journals;
        }

        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin))) {
            int count = in.readInt();
            journals.ensureCapacity(count);

            for (int i = 0; i < count; ++i) {
                journals.add((String)in.readObject());
            }
        } catch (IOException | ClassNotFoundException ex) {
            MainClass.handleException(null, ex);
        }

        return journals;
    }

    public void loadFriends(LJAccount account) {
        account.clearFriends();

        File fin = new File(getCacheDirectory(), FRIENDS_FILE);
        if (!fin.exists()) {
            return;
        }

        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin)))  {
            int count = in.readInt();
            for (int i = 0; i < count; ++i) {
                LJFriend f = (LJFriend)in.readObject();
                if (f != null) {
                    account.restoreFriend(f);
                }
            }
        } catch (IOException | ClassNotFoundException ex) {
            MainClass.handleException(null, ex);
        }
    }

    public void storeFriends(LJAccount account) {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), FRIENDS_FILE)))) {
            final ImmutableList<LJFriend> set = account.getFriends();
            out.writeInt(set.size());
            for (LJFriend f : set) {
                out.writeObject(f);
            }
        } catch (Exception ex) {
            MainClass.handleException(null, ex);
        }
    }

    public void loadBanned() throws IOException, ClassNotFoundException {
        bannedUsers.clear();

        File fin = new File(getCacheDirectory(), BANNED_FILE);
        if (!fin.exists()) {
            return;
        }

        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin))) {
            int count = in.readInt();
            for (int i = 0; i < count; ++i) {
                LJBannedUser user = (LJBannedUser)in.readObject();
                if (user != null) {
                    bannedUsers.add(user);
                }
            }
        }
    }

    public void storeBanned() throws IOException {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), BANNED_FILE)))) {
            out.writeInt(bannedUsers.size());
            for (LJBannedUser user : bannedUsers) {
                out.writeObject(user);
            }
        }
    }

    public boolean loadUserpic(LJUserpic upic) {
        File upicDir = new File(getCacheDirectory(), "userpics");
        if (!upicDir.exists()) {
            return false;
        }

        try {
            URL url = new URL(upic.getUrl());
            String fName = MD5.encode(url.toString()) + ".png";
            File upicFile = new File(upicDir, fName);
            if (!upicFile.exists()) {
                return false;
            }
            ImageIcon image = new ImageIcon(upicFile.getAbsolutePath());
            if (image.getImageLoadStatus() != java.awt.MediaTracker.COMPLETE) {
                return false;
            } else {
                userpicImages.put(upic, image);
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }

    public void loadUserpics(final ArrayList<LJUserpic> userpics) {
        userpics.clear();

        File fin = new File(getCacheDirectory(), USERPICS_FILE);
        if (!fin.exists()) {
            return;
        }

        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin))) {
            int count = in.readInt();
            for (int i = 0; i < count; ++i) {
                LJUserpic upic = (LJUserpic)in.readObject();
                if (upic != null) {
                    userpics.add(upic);
                }
            }
        } catch (IOException | ClassNotFoundException ex) {
            MainClass.handleException(null, ex);
        }
    }

    public void loadUserpicsOffline(LJAccount account) {
        ArrayList<LJUserpic> userpics = new ArrayList<>();
        loadUserpics(userpics);

        File upicDir = new File(getCacheDirectory(), "userpics");
        if (upicDir.exists()) {
            try {
                for (LJUserpic upic : userpics) {
                    String fName = MD5.encode(upic.getUrl()) + ".png";
                    File upicFile = new File(upicDir, fName);
                    ImageIcon image = new ImageIcon(upicFile.getAbsolutePath());
                    if (image.getImageLoadStatus() == java.awt.MediaTracker.COMPLETE) {
                        userpicImages.put(upic, image);
                    }
                }
            } catch (Exception ex) {
                MainClass.handleException(null, ex);
            }
        }

        account.setUserpics(userpics);
    }

    public void loadUserpics(LJAccount account) {
        ArrayList<LJUserpic> userpics = account.getUserpics();

        int count = userpics.size();

        for (int i = 0; i < count; i++) {
            try {
                LJUserpic upic = userpics.get(i);
                if (!loadUserpic(upic)) {
                    URL url = new URL(upic.getUrl());
                    URLConnection conn = url.openConnection();
                    java.awt.image.BufferedImage bim = javax.imageio.ImageIO.read(conn.getInputStream());
                    if (bim != null) {
                        userpicImages.put(upic, new ImageIcon(bim));
                        storeUserpic(upic, bim);
                    }
                }
            } catch (IOException e) {
            }
        }
    }

    public void storeUserpic(LJUserpic upic, java.awt.image.BufferedImage bim) {
        try {
            URL url = new URL(upic.getUrl());
            File upicDir = new File(getCacheDirectory(), "userpics");
            if (!upicDir.exists()) {
                upicDir.mkdir();
            }

            try {
                String fName = MD5.encode(url.toString()) + ".png";
                File upicFile = new File(upicDir, fName);
                javax.imageio.ImageIO.write(bim, "png", upicFile);
            } catch (Exception e) {
                MainClass.handleException(null, e);
            }
        } catch (Exception ex) {
            MainClass.handleException(null, ex);
        }
    }

    public void storeUserpics(ArrayList<LJUserpic> userpics) {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), USERPICS_FILE)))) {
            out.writeInt(userpics.size());
            for (LJUserpic upic : userpics) {
                out.writeObject(upic);
            }
        } catch (Exception ex) {
            MainClass.handleException(null, ex);
        }
    }

    public void loadGroups(LJAccount account) {
        ArrayList<LJGroup> groups = new ArrayList<>();

        File fin = new File(getCacheDirectory(), GROUPS_FILE);
        if (fin.exists()) {
            try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin))) {
                int count = in.readInt();
                groups.ensureCapacity(count);

                for (int i = 0; i < count; ++i) {
                    LJGroup group = (LJGroup)in.readObject();
                    if (group != null) {
                        groups.add(group);
                    }
                }
            } catch (IOException | ClassNotFoundException ex) {
                MainClass.handleException(null, ex);
            }
        }
        account.setGroups(groups);
    }

    public void storeGroups(LJAccount account) {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), GROUPS_FILE)))) {
            int count = account.getGroupsCount();
            out.writeInt(count);
            for (int i = 0; i < count; i++) {
                out.writeObject(account.getGroup(i));
            }
        } catch (Exception ex) {
            MainClass.handleException(null, ex);
        }
    }

    public void loadMoods(ArrayList<LJMood> moods) {
        moods.clear();

        File fin = new File(getCacheDirectory(), MOODS_FILE);
        if (fin.exists()) {
            try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin))) {
                int count = in.readInt();
                moods.ensureCapacity(count);
                maxMoodID = 0;

                for (int i = 0; i < count; ++i) {
                    LJMood mood = (LJMood)in.readObject();
                    if (mood != null) {
                        moods.add(mood);
                        maxMoodID = Math.max(maxMoodID, mood.getID());
                    }
                }
            } catch (IOException | ClassNotFoundException ex) {
                MainClass.handleException(null, ex);
            }
        }
    }

    public void storeMoods(ArrayList<LJMood> moods) throws IOException {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), MOODS_FILE)))) {
            out.writeInt(moods.size());
            for (LJMood m : moods) {
                out.writeObject(m);
            }
        }
    }

    synchronized
    public void storePictures(FBAccount account) {
        ArrayList<FBPicture> pictures = account.getPictures();
        if (pictures == null) {
            return;
        }

        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), PICTURES_FILE)))) {
            out.writeInt(pictures.size());
            for (FBPicture pict : pictures) {
                out.writeObject(pict);
            }
        } catch (Exception ex) {
            MainClass.handleException(null, ex);
        }
    }

    public void loadPictures(FBAccount account) {
        if (account == null) {
            return;
        }

        ArrayList<FBPicture> pictures = new ArrayList<>();
        account.setPictures(pictures);

        File fin = new File(getCacheDirectory(), PICTURES_FILE);
        if (!fin.exists()) {
            return;
        }

        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin))) {
            int count = in.readInt();
            pictures.ensureCapacity(count);

            for (int i = 0; i < count; ++i) {
                FBPicture pict = (FBPicture)in.readObject();
                if (pict != null) {
                    pictures.add(pict);
                }
            }
        } catch (IOException | ClassNotFoundException ex) {
            MainClass.handleException(null, ex);
        }
    }

    public void saveCommentsMetaData(TreeMap<Integer,LJCommentMetaData> commMeta) throws IOException {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), COMM_META_FILE_NAME)))) {
            out.writeInt(commMeta.keySet().size());
            for (Integer key : commMeta.keySet()) {
                LJCommentMetaData meta = commMeta.get(key);
                if (meta != null) {
                    out.writeObject(meta);
                }
            }
        }
    }

    public TreeMap<Integer,LJCommentMetaData> loadCommentsMetaData() throws IOException, ClassNotFoundException {
        TreeMap<Integer,LJCommentMetaData> commMeta = new TreeMap<>();

        File fin = new File(getCacheDirectory(), COMM_META_FILE_NAME);
        if (!fin.exists()) {
            return commMeta;
        }

        try (ObjectInputStream in= new ObjectInputStream(new FileInputStream(fin))) {
            int count = in.readInt();
            for (int i = 0; i < count; ++i) {
                LJCommentMetaData meta = (LJCommentMetaData)in.readObject();
                if (meta != null) {
                    commMeta.put(meta.getID(), meta);
                }
            }
        }

        return commMeta;
    }

    public LJCommentCacheInfo loadCommentsInfo() throws IOException, ClassNotFoundException {
        File fin = new File(getCacheDirectory(), COMMENTS_FILE);
        if (!fin.exists()) {
            return new LJCommentCacheInfo();
        } else {
            try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin)))  {
                return (LJCommentCacheInfo)in.readObject();
            }
        }
    }

    public void storeCommentsInfo(LJCommentCacheInfo info) throws IOException {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), COMMENTS_FILE)))) {
            out.writeObject(info);
        }
    }

    public void storeComments(ArrayList<LJComment> comments, LJCommentCacheInfo info) throws IOException {
        /* Save info */
        storeCommentsInfo(info);

        for (LJComment comm : comments) {
            /* Create directory for posting */
            File dir = getCommentsPostingDirectory(comm.getItemID());
            File file = new File(dir, Integer.toString(comm.getID()) + ".pb");

            try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) {
                out.writeObject(comm);
            }
        }
    }

    public void saveUserMap(TreeMap<Long,String> userMap) throws IOException {
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDirectory(), USERMAP_FILE_NAME)))) {
            out.writeInt(userMap.keySet().size());
            for (Long key : userMap.keySet()) {
                String userName = userMap.get(key);
                if (userName != null) {
                    out.writeObject(key);
                    out.writeObject(userName);
                }
            }
        }
    }

    public TreeMap<Long,String> loadUserMap() throws IOException, ClassNotFoundException {
        TreeMap<Long,String> userMap = new TreeMap<>();

        File fin = new File(getCacheDirectory(), USERMAP_FILE_NAME);
        if (!fin.exists()) {
            return userMap;
        }

        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fin))) {
            int count = in.readInt();
            for (int i = 0; i < count; ++i) {
                Long key = (Long)in.readObject();
                String userName = (String)in.readObject();
                if (key != null && userName != null) {
                    userMap.put(key, userName);
                }
            }
        }

        return userMap;
    }

    public void clearMetaData() {
        File uFile = new File(getCacheDirectory(), USERMAP_FILE_NAME);
        File mFile = new File(getCacheDirectory(), COMM_META_FILE_NAME);
        uFile.delete();
        mFile.delete();
    }

    public void clearComments() {
        File dir = getCommentsDirectory(false);
        if (dir.exists()) {
            File[] files = dir.listFiles();
            for (File f : files) {
                if (f.isDirectory()) {
                    File[] files2 = f.listFiles();
                    for (File f2 : files2) {
                        f2.delete();
                    }
                }

                f.delete();
            }

            dir.delete();
        }
    }

    @Override
    public ProfileDialog createProfileDialog(BloggerFrame frame) {
        return new LJProfileDialog(frame, this);
    }

    @Override
    public ArrayList<AbstractAction> getProfileActions() {
        return profileActions;
    }

    private void createActions() {
        int keyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();

        /*
         * Create Actions
         */

        openFriendsWindowAction = new AbstractAction(L10N.LJPROF_FRIENDS_ACTION.s(), Icon.FRIENDS_WINDOW_ICON.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onFriendsWindow();
            }
        };
        openFriendsWindowAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_1, keyMask));
        openFriendsWindowAction.putValue(Action.SHORT_DESCRIPTION, L10N.LJPROF_FRIENDS_ACTION.s());
        openFriendsWindowAction.putValue(Action.LARGE_ICON_KEY, Icon.FRIENDS_WINDOW_ICON.I());

        editLastPostAction = new AbstractAction(L10N.LJPROF_EDIT_LAST_POST_ACTION.s(), Icon.EMPTY.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onEditLastPost();
            }
        };
        editLastPostAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_L, keyMask));
        editLastPostAction.putValue(Action.SHORT_DESCRIPTION, L10N.LJPROF_EDIT_LAST_POST_ACTION.s());

        historyWindowAction = new HistoryFrameAction();
        historyWindowAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_2, keyMask));

        outboxAction = new OutboxFrameAction();
        outboxAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_4, keyMask));

        if (fbAccount != null) {
            galleryAction = new AbstractAction(L10N.LJPROF_GALLERY_ACTION.s(), Icon.GALLERIES.i()) {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    onGallery();
                }
            };
            galleryAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_3, keyMask));
            galleryAction.putValue(Action.SHORT_DESCRIPTION, L10N.LJPROF_GALLERY_ACTION.s());
            galleryAction.putValue(Action.LARGE_ICON_KEY, Icon.GALLERIES.I());
        }

        consoleAction = new AbstractAction(L10N.LJPROF_ADMIN_CONSOLE_ACTION.s(), Icon.CONSOLE.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onConsole();
            }
        };
        consoleAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_5, keyMask));
        consoleAction.putValue(Action.SHORT_DESCRIPTION, L10N.LJPROF_ADMIN_CONSOLE_ACTION.s());
        consoleAction.putValue(Action.LARGE_ICON_KEY, Icon.CONSOLE.I());

        recentEntriesAction = new AbstractAction(L10N.LJPROF_RECENT_ENTRIES_ACTION.s(), Icon.EARTH.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openAccountLink("");
            }
        };
        recentEntriesAction.putValue(Action.SHORT_DESCRIPTION, L10N.LJPROF_RECENT_ENTRIES_ACTION.s());

        calendarAction = new AbstractAction(L10N.LJPROF_CALENDAR_ACTION.s(), Icon.EARTH.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openAccountLink("calendar");
            }
        };
        calendarAction.putValue(Action.SHORT_DESCRIPTION, L10N.LJPROF_CALENDAR_ACTION.s());

        webFriendsAction = new AbstractAction(L10N.LJPROF_WEB_FRIENDS_ACTION.s(), Icon.EARTH.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openAccountLink("friends");
            }
        };
        webFriendsAction.putValue(Action.SHORT_DESCRIPTION, L10N.LJPROF_WEB_FRIENDS_ACTION.s());

        profileActions.add(getNewPostAction());
        profileActions.add(editLastPostAction);
        profileActions.add(null);
        profileActions.add(openFriendsWindowAction);
        profileActions.add(historyWindowAction);
        if (fbAccount != null) {
            profileActions.add(galleryAction);
        }
        profileActions.add(outboxAction);
        profileActions.add(consoleAction);
        profileActions.add(null);
        profileActions.add(recentEntriesAction);
        profileActions.add(calendarAction);
        profileActions.add(webFriendsAction);

        toolBarActions = new ArrayList<>();

        toolBarActions.add(openFriendsWindowAction);
        toolBarActions.add(historyWindowAction);
        if (fbAccount != null) {
            toolBarActions.add(galleryAction);
        }
        toolBarActions.add(outboxAction);
        toolBarActions.add(consoleAction);

        /*
        _toolbarActions = new AbstractAction[] {
            addFriendAction,
            openFriendsWindowAction,
            historyWindowAction,
            galleryAction,
            null,
            insertFriendAction,
            friendsMenuAction,
            insertCommunityAction,
            communitiesMenuAction,
            null,
            ljCutAction,
            ljCutMenuAction,
        };
         */
    }

    private void onEditLastPost() {
        new OpenPostThread(this, "-1", getUserName()).execute();
    }

    private void onFriendsWindow() {
        JFrame frame = findFrame(FriendsFrame.class);
        if (frame != null) {
            frame.setVisible(true);
        } else {
            new FriendsFrame(this, _account).setVisible(true);
        }
    }

    @Override
    public void onHistoryFrameAction() {
        JFrame frame = findFrame(LJHistoryFrame.class);
        if (frame != null) {
            frame.setVisible(true);
        } else {
            new LJHistoryFrame(this).setVisible(true);
        }
    }

    private void onGallery() {
        if (fbAccount == null) {
            return;
        }

        JFrame frame = findFrame(FotoBilderFrame.class);
        if (frame != null) {
            frame.setVisible(true);
        } else {
            new FotoBilderFrame(this).setVisible(true);
        }
    }

    private void onConsole() {
        JFrame frame = findFrame(AdminConsoleFrame.class);
        if (frame != null) {
            frame.setVisible(true);
        } else {
            new AdminConsoleFrame(this).setVisible(true);
        }
    }

    @Override
    public void onOutboxFrameAction() {
        JFrame frame = findFrame(LJOutboxFrame.class);
        if (frame != null) {
            frame.setVisible(true);
        } else {
            new LJOutboxFrame(this).setVisible(true);
        }
    }

    private void openAccountLink(String suffix) {
        StringBuilder b = new StringBuilder(_account.getProperties().getUsersURL());
        b.append(getUserName());
        b.append("/");
        b.append(suffix);
        OSUtil.runBrowser(b.toString());
    }

    public AbstractAction getOpenFriendsWindowAction() {
        return openFriendsWindowAction;
    }

    public LJEditorFrame findPostWindowForPost(final String id, final String useJournal) {
        return WindowManager.find(LJEditorFrame.class, new WindowManagerEnumerator<LJEditorFrame>() {
            @Override
            public boolean frameFound(LJEditorFrame frame) {
                return ((frame.getPostID().equals(id)) && (frame.getUseJournal().equals(useJournal)));
            }
        });
    }

    @Override
    public LJEditorFrame findBlogEntryEditor(final LJEvent post) {
        if (post == null) {
            return null;
        }

        return WindowManager.find(LJEditorFrame.class, new WindowManagerEnumerator<LJEditorFrame>() {
            @Override
            public boolean frameFound(LJEditorFrame frame) {
                return frame.getPost().equals(post);
            }
        });
    }

    public LJCommentsFrame findCommentsWindowForPost(final LJEvent event) {
        if (event == null) {
            return null;
        }

        return (LJCommentsFrame)WindowManager.find(LJCommentsFrame.class, new WindowManagerEnumerator<LJCommentsFrame>() {
            @Override
            public boolean frameFound(LJCommentsFrame frame) {
                return frame.getItemID().equals(event.getId());
            }
        });
    }

    public void openCommentsWindow(LJEvent event) {
        LJCommentsFrame wnd = findCommentsWindowForPost(event);

        try {
            if (wnd == null) {
                wnd = new LJCommentsFrame(this, event);
            }

            wnd.setVisible(true);
        } catch (LJException e) {
            MainClass.handleException(null, e);
        }
    }

    @Override
    public String getProfileMenuName() {
        return L10N.LIVEJOURNAL_MENU_NAME.s();
    }

    @Override
    public ArrayList<AbstractAction> getProfileToolBarActions() {
        return toolBarActions;
    }

    @Override
    public boolean login(final boolean store, final boolean offl) {
        final String hPasswd = getHPasswdTemp();

        _account = new LJAccount(properties);
        _account.setClientString("JavaSE-PetrusBlogger/" + AboutDialog.VERSION);

        setOnline(!offl);

        if (hPasswd != null) {
            try {
                int mMoodID = 0;
                loadMoods(_account.getMoods());
                mMoodID = LJUserProfile.getMaxMoodID();

                if (isOnline()) {
                    _account.login(getUserName(), hPasswd, true, mMoodID);
                    try {
                        if (fbAccount != null) {
                            fbAccount.login(getUserName(), hPasswd, true);
                        }
                    } catch (FotoBilderException ex) {
                        fbAccount = null;
                        MainClass.handleException(null, ex);
                    } catch (IOException ex) {

                    }
                    storeSharedJournals(_account.getSharedJournals());
                    storeGroups(_account);
                } else {
                    _account.setLoginName(getUserName());
                    _account.setFullName(getUserName());
                    /* Load shared journals and groups from the cache */
                    _account.setSharedJournals(loadSharedJournals());
                    loadGroups(_account);
                }

                if (Thread.interrupted()) {
                    return false;
                }

                loadFriends(_account);
                loadBanned();

                if (Thread.interrupted()) {
                    return false;
                }

                if (!isOnline()) {
                    loadUserpicsOffline(_account);
                } else {
                    storeUserpics(_account.getUserpics());
                    loadUserpics(_account);
                }

                if (Thread.interrupted()) {
                    return false;
                }

                m_tags = _account.getUserTags();
                if ((loadUserTags(m_tags) == 0) && isOnline()) {
                    try {
                        m_tags = _account.loadUserTags(null);
                    } catch (LJModeNotSupportedException e) {
                        // Do nothing, just ignore
                    }
                    storeUserTags(m_tags);
                }
                // buildTagsMenu(m_tags);                               // Implement this!!!

                if (Thread.interrupted()) {
                    return false;
                }

                if (isOnline()) {
                    loadPictures(fbAccount);
                }

                storeMoods(_account.getMoods());

                if (Thread.interrupted()) {
                    return false;
                }

                /* Load usermap from file */
                LJCommentCacheInfo commInfo = loadCommentsInfo();
                if (getCommentsMetaInfoUpdate() == LJCommentMetaDataUpdate.ONCE) {
                    commInfo.resetMaxID();
                }
                _account.setCommentsInfo(commInfo);
                _account.setUserMap(loadUserMap());
                _account.setCommentsMeta(loadCommentsMetaData());

                if (Thread.interrupted()) {
                    return false;
                }

                setConnected(true);
                setAccount(_account);

                if (getRemindBirthdays()) {
                    checkBirthdays();
                }
                return true;
            } catch (InterruptedException e) {
                return false;
            } catch (Exception e) {
                MainClass.handleException(null, e);
                return false;
            }
        } else {
            return false;
        }
    }

    @Override
    public void postLoginUIActions() {
        historyWindowAction.setEnabled(isOnline());
        if (galleryAction != null) {
            galleryAction.setEnabled(isOnline());
        }
        consoleAction.setEnabled(isOnline());

        /* Start check friends thread */
        checkFriendsStartStop();
    }

    public ArrayList<LJBannedUser> getBannedUsers() {
        return bannedUsers;
    }

    public void setBannedUsers(ArrayList<LJBannedUser> bannedUsers) {
        this.bannedUsers = bannedUsers;
    }

    public LJBannedUser getBannedUser(int index) {
        if ((index >= 0) && (index < bannedUsers.size())) {
            return bannedUsers.get(index);
        } else {
            return null;
        }
    }

    private void checkBirthdays() throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            @Override
            public void run() {
                ArrayList<LJFriend> bList = _account.checkBirthdays(new Date(), getRemindBirthdaysInterval());
                if (!bList.isEmpty()) {
                    BirthdayReminderDialog bDial = new BirthdayReminderDialog(null, bList);
                    bDial.showDialog();
                }
            }
        });
    }

    private void checkFriendsStartStop() {
        synchronized (m_checkTimerSync) {
            if (!getCheckFriends()) {
                if (m_checkFriendsTimer != null) {
                    m_checkFriendsTimer.cancel();
                    m_checkFriendsTimer = null;
                }
            } else {
                if (m_checkFriendsTimer == null) {
                    m_checkFriendsTimer = new java.util.Timer();
                    m_checkFriendsTimer.schedule(new CheckFriendsTask(this, null, getCheckFriendsMask()), 1);
                }
            }
        }
    }

    public void checkFriendsHandle(LJCheckFriendsData checkData) {
        if (checkData.hasNew()) {
            int res = JOptionPane.showConfirmDialog(
                null,
                L10N.CHECK_FRIENDS_NOTIFICATION_MESSAGE.s(),
                AboutDialog.PRODUCT_NAME,
                JOptionPane.YES_NO_OPTION
            );

            if (res == JOptionPane.YES_OPTION) {
                openAccountLink("friends");
            }
        }

        synchronized (m_checkTimerSync) {
            if (m_checkFriendsTimer != null) {
                m_checkFriendsTimer.schedule(new CheckFriendsTask(this, checkData, 1), checkData.getInterval() * 1000);
            }
        }
    }


    @Override
    public void onNewPost() {
        new LJEditorFrame(this, null).setVisible(true);
    }

    static ImageIcon getFriendStatusIcon(LJFriend friend) {
        if (friend.isMutual()) {
            return Icon.MUTUAL_FRIEND_ICON.i();
        }
        if (friend.isFriendOf()) {
            return Icon.FRIENDOF_ICON.i();
        }

        switch (friend.getStatus()) {
            case SUSPENDED:
                return Icon.SUSPENDED_ICON.i();

            case DELETED:
                return Icon.DELETED_ICON.i();

            case PURGED:
                return Icon.PURGED_ICON.i();

            default:
                return Icon.FRIEND_ICON.i();
        }
    }

    @Override
    public IBlogEntry newBlogEntry() {
        return new LJEvent();
    }

    @Override
    public void openBlogEntryEditor(LJEvent entry, File file) {
        new OpenPostThread(this, entry, file).execute();
    }

    @Override
    public void publishEntry(LJEvent entry) throws Exception {
        _account.postEvent(entry);
    }

    @Override
    public void updateEntryAdterRestore(LJEvent entry) {
        // do nothing
    }

    public ImageIcon getUserpicImage(LJUserpic upic) {
        return userpicImages.get(upic);
    }

    @Override
    public String getImageCacheName() {
        return "pictures";
    }

    @Override
    public ImageIcon getIcon() {
        return Icon.LIVEJOURNAL.i();
    }
}
